
/***************************************************/
/* G: IN ORDER TO REMOVE NEW NOTES SEARCH FOR "G:" */
/* SN: Special notice, must go back and consider   */
/* Q: must verify full quit here *******************/
/***************************************************/
/***************************************************/

#include "CommandEngine.h"

int running_flag = 0; /* G: Use it as a general state for unplanned exit?. */
int rand_usage=0; /* G: DELETE? */

/** G: Global variables for the input files, not sure**/
FILE *nodes = NULL;
FILE *edges = NULL;
Network *global_net = NULL;
/*int global_lower_bound = 5;  SN: what is this??*/
#define IS_VALUE_I(X)((1-x)<0.00001)


/*******************************************/
/*---- Network functions (Assignment 2)----*/
/*******************************************/


void addVertex(Network* net, char* verName){

	Vertex* newVer;
	Vertex** vList;
	
	vList = net->vertices;

	if(net->size == 100){

		if(printf("Error: cannot add vertex - too many vertices\n")<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}

		return;

	}


	if(net->size == net->maxSize){
		
		vList = (Vertex**)realloc(vList, 2*net->maxSize*(sizeof(Vertex*)));
		net->vertices = vList;

		if(vList == NULL){
			perror("Error: standard function realloc has failed\n");
			running_flag=0;
			quit(net);
			return;
		}

		net->maxSize = net->maxSize*2;	
	}

	newVer = createVertex(net->size , verName); /* G: I've added 1 to meet the new spec */

	if(newVer == NULL){
		running_flag=0;
		quit(net);
		return;
	}

	vList[net->size] = newVer;

	net->size++;

}


void printDegree(Network* net, int id){

	Vertex* v;
	int deg;
	char str[] = "Error: ID number is not in the system";

	/* Check id validity */
	if(id>=net->size){ /* is it >=  ?? and I'm printing invalid message - must check in forum */
		sec_print(net, str);
		return;
	}

	v = *(net->vertices + id);
	deg = v->degree;

	if(printf("%d\n", deg)<0){
		perror("Error: standard function printf has failed\n");
		running_flag=0;
		quit(net);
		return;
	}
}


void addEdge(Network* net, int firstID, int secondID, double weight){

	Vertex** vertices;
	Edge* newEdge1;
	Edge* newEdge2;
	Vertex* v1;
	Vertex* v2;
	LinkedList* temp1;
	LinkedList* temp2;
	LinkedList* net_list_link;

	/* BEGINNING OF CHANGE */

	if(firstID == secondID){
		if(printf("Error: edge must be between two different vertices\n")<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
		return;
	}

	if(net->size <= firstID || net->size <= secondID){ /* G: a needed change*/
		if(printf("Error: ID number is not in the system\n")<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
		return;
	}
	
	
	
	vertices = net->vertices;
	v1 = vertices[firstID];
	v2 = vertices[secondID];

	/*The next if condition checkes that the new edge doesn't exist allready*/
	temp1 = getEdgeLink(v1->edges, firstID, secondID);
	temp2 = getEdgeLink(v2->edges, firstID, secondID);

	if(temp1 != NULL || temp2 != NULL){
		if(printf("Error: edge is in the graph\n")<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
		return;
	}

	/* What's below was once above... */ 



		if(weight >= 100){
		if(printf("Error: weight parameter must be less than 100\n")<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
		return;
	}
	
	if(net->weightsSum + weight >= 1000){
		if(printf("Error: sum of edges weight must be less than 1000\n")<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
		return;
	}

	newEdge1 = createEdge(firstID, secondID, weight);
	newEdge2 = createEdge(firstID, secondID, weight);

	if(newEdge1 == NULL || newEdge2 == NULL){
		running_flag=0;
		quit(net);
		return;
	}

	v1->edges = HeadInsert (v1->edges, newEdge1);
	if(v1->edges == NULL){
		running_flag=0;
		quit(net);
		return;
	}
	v1->degree++;

	v2->edges = HeadInsert(v2->edges, newEdge2);
	if(v2->edges == NULL){
		running_flag=0;
		quit(net);
		return;
	}
	v2->degree++;

	net->weightsSum = net->weightsSum + weight;
	/*G: I've made 3 additions here - */
	net->totalEdgeNumber = net->totalEdgeNumber + 1;
	newEdge1->edge_id=net->totalEdgeNumber;
	newEdge2->edge_id=net->totalEdgeNumber;
	
	/* G: NEW CODE - add to net edge list*/
	
	net_list_link = (LinkedList *) malloc(sizeof(LinkedList));

	if(net->edge_list_head!=NULL){
		net->edge_list_current->next = net_list_link;
		net_list_link->prev = net->edge_list_current;
	}else{
		net->edge_list_head = net_list_link;
		net_list_link->prev = NULL;
	}
	
	net_list_link->next = NULL;
	net_list_link->e = newEdge1;
	net->edge_list_current = net_list_link;
}


void removeEdge(Network* net, int firstVertexID, int secondVertexID){

	Vertex** vertices;
	Vertex* v1;
	Vertex* v2;
	LinkedList* toDel1;
	LinkedList* toDel2;
	int net_size=net->size;
	double weight;

	/* Check vertices id validity */
	if(firstVertexID>=net_size||secondVertexID>=net_size){
		sec_print(net, "Error: ID number is not in the system");
		return;
	}

	if(firstVertexID==secondVertexID){
		sec_print(net, "Error: edge is not in the graph");
		return;
	}

	/* END of: Check vertices id validity */
	
	vertices = net->vertices;
	v1 = vertices[firstVertexID];
	v2 = vertices[secondVertexID];

	toDel1 = getEdgeLink(v1->edges, firstVertexID, secondVertexID);
	toDel2 = getEdgeLink(v2->edges, firstVertexID, secondVertexID);

	if(toDel1 == NULL || toDel2 == NULL){
		sec_print(net, "Error: edge is not in the graph");
		return;
	}
	
	weight = toDel1->e->weight;
	net->weightsSum -= weight;

	v1->edges = DeleteItem(toDel1);
	v2->edges = DeleteItem(toDel2);

	v1->degree--;
	v2->degree--;

}


void idByName(Network* net, char* name){

	Vertex** verticesList;
	Vertex* currVertex;
	int numOfVertex = net->size;
	int index, 	found_vertex=0;
	char* currName;

	verticesList = net->vertices;
	
	for (index = 0; index < numOfVertex; index++){

		currVertex = *(verticesList + index);
		currName = currVertex->name;
	

		if (strcmp(name, currName) == 0){
			found_vertex=1;
			if(printf("%d\n", currVertex->id)<0){
				perror("Error: standard function printf has failed\n");
				running_flag=0;
				quit(net);
				return;
			}
		}
	}

	if(found_vertex==0)
		sec_print(net, "Error: vertex name is not in the system");
}


void print(Network* net){

	Vertex** vertices;
	Vertex* currV;
	Vertex* v2;
	LinkedList* listEdges;
	Edge* currE;
	int flag = 0;
	int index;

	if(net->size == 0){
		if(printf("\n")<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
		return;
	}

	vertices = net->vertices;

	if(printf("%d vertices:\n", net->size)<0){
		perror("Error: standard function printf has failed\n");
		running_flag=0;
		quit(net);
		return;
	}

	for(index = 0; index<net->size; index++){

		currV = vertices[index];
		if(printf("%d: %s\n", currV->id, currV->name)<0){  /*G: made a little change here */
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}

		if(flag == 0){
			listEdges = currV->edges;
			if(listEdges != NULL)
				flag = 1;
		}
	}

	if(flag == 0){
		return;
	}

	if(printf("edges:\n")<0){
		perror("Error: standard function printf has failed\n");
		running_flag=0;
		quit(net);
		return;
	}
	for(index = 0; index < net->size; index++){

		currV = vertices[index];
		listEdges = currV->edges;

		while(listEdges != NULL){

			currE = listEdges->e;
			if(currE == NULL){
				continue;
			}
			if(currV->id == currE->id1){
				v2 = vertices[currE->id2];
			}
			else{
				v2 = vertices[currE->id1];
			}
			if(currV->id < v2->id){
				
				/*if(printf("%s %s %lf\n", currV->name, v2->name, currE->weight)<0){ I've made a change here  ! ! ! ! */
				if(printf("%s %s %f\n", v2->name, currV->name, currE->weight)<0){
					perror("Error: standard function printf has failed\n");
					running_flag=0;
					quit(net);
					return;
				}
			}

			listEdges = listEdges->next;
		}
	}

}


void cluster(Network* net, int numOfClusters){

	double random_clustering_score=0, weight=0;
	int vertex_id;
	int i=0;
	int num_of_vertices=net->size;
	Vertex* vertex;
	Vertex** vertices=net->vertices;
	LinkedList* edge_list;
	Edge* current_edge;

		
	if(numOfClusters<2){
		sec_print(net, "Error: number of clusters parameter must be an integer type bigger than 1");
		return; 
	}

	/* Initialize rand the with the first run of cluster */
	if(rand_usage==0){ 
		srand(23);
		rand_usage=1;
	}

	/* clustering loop */
	for(i=0; i<num_of_vertices; i++){
		vertex=vertices[i]; /*line: 233 */
		vertex->clusterID=rand()%numOfClusters;
	}

	if(printf("%d vertices:\n", num_of_vertices)<0){
		perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
	}
	
	
	/* Calculating & printing loop */
	
	for(i=0; i<num_of_vertices; i++){
		vertex=*(vertices + i); /*line: 226*/
		edge_list=vertex->edges;
		vertex_id=vertex->id;

		if(printf("%s %d\n", vertex->name, vertex->clusterID)<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
		
		if(edge_list!=NULL){
			while(1){
				current_edge=edge_list->e;
				weight=current_edge->weight;
				if((vertices[current_edge->id1]->clusterID==vertices[current_edge->id2]->clusterID)&&(current_edge->id1==vertex_id))
					random_clustering_score+=weight;
				if((vertices[current_edge->id1]->clusterID!=vertices[current_edge->id2]->clusterID)&&(current_edge->id1==vertex_id))
					random_clustering_score-=weight;
				if(edge_list->next==NULL)
					break;
				edge_list=edge_list->next;
			}
		}
	}



	/* WRAP needed */
	if(printf("The random clustering score for %d clusters is %f\n", numOfClusters, random_clustering_score)<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return;
		}
	 
}


void quit(Network* net){

	Vertex** vertices;
	Vertex* currV;
	LinkedList* edges;
	LinkedList* tempLink;
	int index;

	if(net->size == 0){
		free(net->vertices);
		free(net);
		return;
	}
	vertices = net->vertices;

	for(index = 0; index < net->size; index++){

		currV = vertices[index];
		edges = currV->edges;

		while (edges != NULL){
			tempLink = edges;
			edges = edges->next;
			free(tempLink->e);
			free(tempLink);
		}
	}

	free(vertices);
	free(net);

}


/***************************************/
/*---- input processing ENGINE ----*/
/***************************************/


/* G: New ignition point */
void main_engine(Network* net, char **argv)	{
	
	int upper_bound, lower_bound;
	int i;

	/*G: We should use FLAG for a general state - 0 means "GET OUT AND FREE MEMORY*/
	running_flag = 1;
	
	global_net=net;
	
	/* Stage 1 - build network from input */
	handle_user_input(argv);
	
	lower_bound = char_to_int(global_net, argv[3], 1);
	upper_bound = char_to_int(global_net, argv[4], 1); /* G: possible problem - 3rd argument to char_to_int */
	
	
	/* Stage 2 - preparing data for CPLEX */
	/*Will be done in cluster.c ?*/

	/* G: QA*/
	/*
	for(i=lower_bound; i<=upper_bound; i++){
		create_objective_array(i);
		build_constraint_memory(i);
	}
	*/	

	/* Stage 3 - initializing CPLEX environment */
	/*Will be done in cluster.c ?*/



	/****************/
	/* TESTING ZONE */
	/****************/
	

}


/***********************************/
/* Parsing & input check utilities */ 
/***********************************/

/*---- Parsing mechanism ----*/

/* Returns number of parameters in input
	- index - enter input's 1st param (i.e - command type) length
	- skips whitespaces
	- ingnores 1st parameter according to index argument
*/
int number_of_parameters(char *input){
	int i = 0;
	int j = 0;
	
	while(i<30){
		if(input[i]=='\0')
			break;
		if(input[i]!=' ')
			j++;
		while((input[i]!=' ')&&(i<30)){
				i++;			
			}
		while((input[i]==' ')&&(i<30)){
				i++;
			}
	}
	return j;	
}


/* Returns the 1st parameter/argument following the given index */ 
char* get_next_parameter(char *input, char* parameter){
	int i=0, j=0;
	char tmp[30];
	
	while(isspace(input[i])!=0){ 
		i++; /* Get rid of annoying whitespaces prior to the first param */
	}

	while((isspace(input[i])==0)){  
		if(input[i]=='-'){
			input[i]=' ';
			break; /* '-' separates the node names of an edge */
		}
		tmp[j]=input[i];
		if(input[i]=='\0') break;
		input[i]=' ';
		j++;
		i++;
	}
	
	tmp[j]='\0'; 
	strcpy(parameter, tmp);
	return parameter;
}


/* Returns the number of whitespaces at the beggining of each line (before command/1st argument) */
int whitespace_shift(char *input){
	int i=0;
	
	while(i<30){
		if(isspace(input[i])){
			i++;
		}else{
			break;
		}
	}

	return i;

}


/*---- Input check ----*/

/* checking whether or not input has only whitespaces, or is empty (E.C #1) */
int check_only_whitespace(Network* net, char *input){
	int i=0;
	int len = strlen(input);

	while(i<len){
		if(isspace(input[i])==0)
			return 1;
		i++;
	}
	sec_print(net, "Error: command must have at least one character");
	return 0;
}


/* Checking number's validity and converting string to int (S.P #2), if fails returns -1 */
int char_to_int(Network* net, char* number, int op){
	int i=0, int_form=-1;
	sec_print(net, "NO argumnet was GIVEN!"); /*SN: This should be handled outside, return -2 here or some other special code*/
	if(number == NULL) return -1;

	/* check if string is made of only number digits. if not - returns -1 */
	while(number[i]!='\0'){
		if(number[i]>='0'&&number[i]<='9'){
			i++;
		}else{
			if(op==6){
				sec_print(net, "Error: number of clusters parameter must be an integer type bigger than 1");
				return -1;
			}
			sec_print(net, "Error: ID parameter is not a non-negative integer"); /*IS IT?! I don't think that sholud be thrown in this case. CHECK AGAIN*/
			return -1;
		}
	}

	int_form=atoi(number);
	if(int_form>2147483647||((!str_vs_int(number, int_form)))){ /*IS IT OK??*/
		sec_print(net, "Error: ID parameter is not a non-negative integer");
		return -1;
	}
	return int_form;
}


/* Checking number's validity and converting string to int (S.P #3), if fails returns -1 */
double char_to_double(Network* net, char* number){
	int i=0;
	double d_form = -1;
	int came_across_a_dot = 0;

	/* check if string's validity. if not valid, return -1 */
	while(number[i]!='\0'){
		if(number[i]<'0'||number[i]>'9'){ 
			if(number[i]=='.'&&came_across_a_dot==0){
				came_across_a_dot=1;
				i++;
				continue;
			}
			sec_print(net, "Error: weight parameter is not a non-negative double");
			return d_form;
		}
		i++;
	}

	d_form=atof(number);
	if(d_form<0){ /* '-', '+' signs are rejected, WHAT? this is redundant.*/
		sec_print(net, "Error: weight parameter is not a non-negative double");
		return -1;
	}
	
	return d_form;
}


int sec_print(Network* net, char* str){
	if(printf("%s\n", str)<0){
			perror("Error: standard function printf has failed\n");
			running_flag=0;
			quit(net);
			return -1;
		}
	return 1;
}


int str_vs_int(char* str, int num){
	int len, i, digit, char_digit;
	
	

	len = strlen(str);
	for(i=len-1; i>=0; i--){
		digit = (num - (num/10)*10);
		num = num/10;
		char_digit = str[i]-48;
		if(digit!=char_digit)
			return 0;
	}

	return 1;
}


/*****************************************************************/
/******************* final proj. new functions *******************/
/*****************************************************************/

/* Returns vertex id, by name. Terible code duplication !!! */
int get_id(Network* net, char* name){

	Vertex** verticesList;
	Vertex* currVertex;
	int numOfVertex = net->size;
	int index;
	char* currName;

	verticesList = net->vertices;
	
	for (index = 0; index < numOfVertex; index++){

		currVertex = *(verticesList + index);
		currName = currVertex->name;
	

		if (strcmp(name, currName) == 0)
			return currVertex->id;
	}

		sec_print(net, "Error: vertex name is not in the system");
		return -1;
}


/*This function opens the files nodes and edges in input folder and reads the network from them.*/
void handle_user_input(char** argv){
	
	char *nodes_path, *edges_path; 

	/*The main program gets 4 arguments from the user: 
		i.   Input folder (relative path + slash)
		ii. Output folder (relative path + slash)
		iii. Lower bound for the number of clusters: L
		iv. Upper bound for the number of clusters: U */
	/* SN: Need to relate to special cases - go through the forum */
	
	/* Prepare nodes path */
	nodes_path = (char*)malloc(sizeof(char)*strlen(argv[1]) + 5 +1);
	strcpy (nodes_path, argv[1]);
	strcat (nodes_path,"nodes");
	
	/* Prepare edges path */
	edges_path = (char*)malloc(sizeof(char)*strlen(argv[2]) + 5 +1);
	strcpy (edges_path, argv[2]);
	strcat (edges_path,"edges");
	
	/* Open files, then send to net builder */
	
	nodes = fopen(nodes_path, "r");
	if(nodes==NULL){
		printf("ERROR!, can't open MF nodes file.. try again later");
		assert(nodes==NULL); /* CHANGE, this is wrong*/
	} 
	
	edges = fopen(edges_path, "r");
	if(edges==NULL){
		printf("ERROR!, can't open MF edges file.. try again later");
		assert(edges==NULL);
	} 
	
	build_network(global_net);

	fclose(nodes);
	fclose(edges);
	/*G: NEED TO VERIFY/ASSERT after closing*/
}


/*This function builds the network out of the input files.*/
void build_network(Network *net){
	char input_data[501], node_name[501], edge_data[501], trash_bin[501]; /*maximum line length is 500...*/
	int i=0, first_vertex_id = 0, second_vertex_id = 0;
	double weight = 0;

	/* Add nodes from input */

	while(!feof(nodes)){
		fgets(input_data, 501, nodes);
		get_next_parameter(input_data, trash_bin);
		/* G: if(trash_bin==NULL) break;*/
		get_next_parameter(input_data, node_name);
		if(strlen(node_name)==0) break;
		addVertex(net, node_name);	
		}

	/* add edges from input */
			
	while(!feof(edges)){

		fgets(input_data, 501, edges);

		/* Get rid of "interaction:" */
		get_next_parameter(input_data, edge_data);

		/* Fetch the first parameter */
		get_next_parameter(input_data, edge_data);
		/* G:DEBUGGING printf("edgeData1: %s, ", edge_data);*/
		first_vertex_id = get_id(net, edge_data);
		if(first_vertex_id==-1){ /*meaning - first_vertex_id is not a valid int number*/
			printf("Error! first_vertex_id is not a valid int number\n");
			continue;
		}
		/* Fetch the second parameter */
		get_next_parameter(input_data, edge_data);
		/* G:DEBUGGING printf("edgeData2: %s, ", edge_data); */
		second_vertex_id = get_id(net, edge_data);
		if(second_vertex_id==-1){ /*meaning - second_vertex_id is not a valid int number*/
			printf("Error! second_vertex_id is not a valid int number\n");
			continue;
		}
		/* Fetch the weight */
		get_next_parameter(input_data, edge_data);
		weight = char_to_double(net, edge_data); 
		if(weight==-1) /*meaning - weight is not a valid double number*/
			continue;
		/* G:DEBUGGING printf("weight is: %s \n", edge_data);*/

		
		addEdge(net, first_vertex_id, second_vertex_id, weight);
		/*if(i%10 == 0) print(net); USED FOR DEBUGGING*/
		i++;
	}


}


/**************************/
/* TESTING ZONE functions */
/**************************/


void create_objective_array(int number_of_clusters){
	int i, j, num_of_edges, num_of_ver;
	double *obj;
	vertex_iterator ver_iter;
	edge_iterator edge_iter;

	/*objsen = CPX_MAX*/
	
	/*initialize iterators*/
	new_vertex_iterator(global_net, &ver_iter);
	new_edge_iterator(global_net, &edge_iter);
	
	num_of_edges = global_net->totalEdgeNumber;
	num_of_ver = global_net->size;

	/* allocate memory for OBJ array */
	obj = (double *)malloc(sizeof(double)*(num_of_edges + num_of_ver)*number_of_clusters);
    if(obj == NULL){  /* G: must update "quit" function to deal with the new requirments*/
		quit(global_net);
		return;
	}

	/* build OBJ array */
	/* Inserting weight values for edges variables */
	for(j=0; j<num_of_edges; j++){
		for(i=0; i<number_of_clusters;i++){
			obj[j+i*num_of_edges]=edge_iter.currnet_edge->weight;
		}
		next_edge_NEW(&edge_iter);
	}; 
	
	/* Inserting 0 values for vertices variables */
	for(i=num_of_edges*number_of_clusters; i<(num_of_edges + num_of_ver)*number_of_clusters; i++){
		obj[i] = 0; 
	}
	
	/* QA */
	/*printf("\n\nObjective array ordered by clusters:...\n");
	for(i=0; i<number_of_clusters;i++){
		printf("Cluster# %d: ", i+1);
		for(j=0; j<num_of_edges;j++)
			printf("%f, ", obj[i*num_of_edges+j]);
		printf("\n");
	}*/
	/* print OBJ array*/
	/*for(i=0; i<(num_of_edges + num_of_ver)*number_of_clusters; i++){
		printf("%f ",  obj[i]);
	}*/

}


int allocation_verifier(int* array){
	if(array == NULL){
		perror("Error: standard function malloc has failed\n");
		return 0;
	}
	return 1;
}


void build_constraint_memory(int number_of_clusters){
	
	char *sense = NULL;
	double *rhs = NULL;
	int *matbeg=NULL;
	int *matcnt= NULL;
	int *matind= NULL;
	int *matval= NULL;
	int cnt;
	int *indices = NULL;
	char *ctype = NULL;
	
	int beg_size, ind_size, number_of_constraints, number_of_variables, num_of_var_instances, edges_num, vertices_num;
	int i, j, instances_counter, cur_var_instances, cur_indval_index, cur_shifted_indval_index, constraint_id, cluster_counter;
	Vertex *cur_vertex= NULL, *vertex_1, *vertex_2;
	Vertex **vertices_arr = global_net->vertices;
	Edge *cur_edge= NULL;
	edge_iterator edge_iter;
	vertex_iterator ver_iter;

	/* initialize CPLEX arrays */
	edges_num = global_net->totalEdgeNumber;
	vertices_num = global_net->size;

	number_of_constraints = (3 * number_of_clusters*global_net->totalEdgeNumber) + (vertices_num) + number_of_clusters;  /*Total # of constraints: 3*k*|E| + |V| + k*/
	number_of_variables = number_of_clusters*(edges_num+vertices_num); /* Total number of variables= k*(|E|+|V|) */
	num_of_var_instances = number_of_clusters*(7*edges_num+2*vertices_num); /* Total # of instances: k*(7|E|+2|V|) */

	beg_size = number_of_variables; /* # of variables */
	ind_size = num_of_var_instances; /*# of all variables instances */

	/* Memory allocation + Verification- free when done */
	matbeg = (int*)malloc(sizeof(int)*beg_size); /* where the variable starts. malloc size according to serial id of the variable */
	matcnt = (int*)malloc(sizeof(int)*sizeof(int)*beg_size); /* malloc size according to serial id of the variable */
	matind = (int*)malloc(sizeof(int)*ind_size); /* Constraint's id. Total number of vars instances (NOT INCLUDING 0's) */
	matval = (int*)malloc(sizeof(int)*ind_size); /* value in the constraint. Total number of vars instances (NOT INCLUDING 0's) */
	sense = (char*)malloc(sizeof(char)*number_of_constraints);
	rhs = (double*)malloc(sizeof(double)*number_of_constraints);
	indices = (int*)malloc(sizeof(int)*number_of_variables);
	ctype = (char*)malloc(sizeof(char)*number_of_variables);


	/*alloc. verification, SN: should I free the problematique one? What message should I display? try allocate again? */
	if((allocation_verifier(matbeg)==0)||(allocation_verifier(matcnt)==0)||(allocation_verifier(matind)==0)||(allocation_verifier(matval)==0)||rhs==NULL||sense==NULL){
		free(matbeg); /* Q: verify full exit LOGIC here */
		free(matcnt);
		free(matind);
		free(matval);
		free(sense);
		free(rhs);
		quit(global_net); /* Q: verify full exit LOGIC here */
		return;
	}; 

	/* Fill in matbeg & matcnt */
	/* matbeg[i]&matcnt[i] refers to the same variable. Order is X_i_k and then Z_j_k, X-vertices, Z-edges, k-cluster*/
	
	/* Fill in vertices variables for matbeg & matcnt */
	/* Edges - Z_a_b */
	instances_counter = 0;
	new_edge_iterator(global_net, &edge_iter);
	for(i=0; i<edges_num*number_of_clusters; i+=number_of_clusters){
		cur_edge = edge_iter.currnet_edge;
		cur_edge->matbeg_id = instances_counter;
		cur_edge->indval_index = cur_edge->matbeg_id;
		for(j=0; j< number_of_clusters; j++){
			matbeg[i+j] = instances_counter; /* i = edge_id -1*/
			matcnt[i+j] = 3;
			instances_counter +=3;
		}
		next_edge_NEW(&edge_iter);
	}
	
	/* Vertices - X_a_b */
	/* SN: must replace OLD iterator*/
	new_vertex_iterator(global_net, &ver_iter);
	for(i=edges_num*number_of_clusters ; i<(edges_num + vertices_num)*number_of_clusters; i+=number_of_clusters){
		cur_vertex = ver_iter.currnet_vertex;
		cur_vertex->indval_index = instances_counter;
		cur_vertex->matbeg_id = instances_counter;
		cur_var_instances = 2*cur_vertex->degree + 2; /*2* vertex.degree+2*/
		cur_vertex->instance_number = cur_var_instances;
		for(j=0; j< number_of_clusters; j++){
			matbeg[i+j] = instances_counter;
			matcnt[i+j] = cur_var_instances;
			instances_counter += cur_var_instances; /* #ofVertexInstances = 2*vertex.degree+2 */
		}
		next_vertex_NEW(&ver_iter); /* SN: this isn't secure !!! MUST WRAP !!!*/
	}

	/* G: QA purposes - DELETE qa1(2, number_of_constraints, beg_size, ind_size, matbeg, matcnt, matind, matval, sense, rhs);*/

	/* CONSTRAINT TYPE i */
	
	new_edge_iterator(global_net, &edge_iter);
	constraint_id = 0;
	for(i=0; i<edges_num; i++){ /*1 iteration for every edge and every cluster (specific Z_a_b in each iteration)*/
		
		cur_edge = edge_iter.currnet_edge; /*SN: might be problematique*/

		for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){ 
			
			cur_vertex = vertices_arr[cur_edge->id1];

			for(j=1; j<=2; j++){ /* Edge "i", cluster "cluster_counter", vertex "j" */

				/* Constraint's data */
				/* OLD CLACULATION - */
				/*constraint_id = 2*number_of_clusters*i + (cluster_counter - 1)*number_of_clusters + j - 1; */
				/* 4*edge_id + cluster_id*num_of_clusters + vertex_1_or_2*/
				
				sense[constraint_id]='L';
				rhs[constraint_id]=0;
				constraint_id ++;

				/* Edge data */
				cur_shifted_indval_index = cur_edge->indval_index + cluster_counter-1;
				matind[cur_shifted_indval_index] = constraint_id; /* Constraint's number */
				matval[cur_shifted_indval_index] = 1; /* Value for edge Z_i_j */

				/* Vertex data */
				cur_indval_index = cur_vertex->indval_index; /*Where current vertex begins. indval_index is initially taken from instances counter whlie initializing matbeg for vertices*/
				cur_shifted_indval_index = cur_indval_index + (cluster_counter - 1)*cur_vertex->instance_number; /* compansation for correct VERTEX_CLUSTER variable*/
				matind[cur_shifted_indval_index] = constraint_id; 
				matval[cur_shifted_indval_index] = -1;	

				/* index increment */
				
				if(cluster_counter==number_of_clusters){
					cur_vertex->indval_index++ ;
				}
				cur_edge->indval_index++ ;
				cur_vertex = vertices_arr[cur_edge->id2];
			}

		}

		/*Continue to next Edge */
		cur_edge->indval_index = cur_edge->matbeg_id+2; /* A little fix for a stupid calculation*/
		next_edge_NEW(&edge_iter);
		cur_edge = edge_iter.currnet_edge;
	} /* END OF TYPE i*/

	new_edge_iterator(global_net, &edge_iter);
	new_vertex_iterator(global_net, &ver_iter);

	/* CONSTRAINT TYPE ii */

	for(i=0; i<edges_num; i++){ /*1 iteration for every edge and every cluster (specific Z_a_b in each iteration)*/
		
		cur_edge = edge_iter.currnet_edge; /*SN: might be problematique*/
		vertex_1 = vertices_arr[cur_edge->id1];
		vertex_2 = vertices_arr[cur_edge->id2];

		for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){ 

			sense[constraint_id]='G';
			rhs[constraint_id]=-1;

			/* Edge data */
			cur_shifted_indval_index = cur_edge->indval_index + 3*(cluster_counter-1);
			matind[cur_shifted_indval_index] = constraint_id; /* Constraint's number */
			matval[cur_shifted_indval_index] = 1; /* Value for edge Z_i_j */

			/* Vertex 1 data */
			cur_indval_index = vertex_1->indval_index; /*Where current vertex begins. indval_index is initially taken from instances counter whlie initializing matbeg for vertices*/
			cur_shifted_indval_index = cur_indval_index + (cluster_counter - 1)*vertex_1->instance_number; /* compansation for correct VERTEX_CLUSTER variable*/
			matind[cur_shifted_indval_index] = constraint_id; 
			matval[cur_shifted_indval_index] = -1;	/*Change to -1*/

			/* Vertex 2 data */
			cur_indval_index = vertex_2->indval_index; /*Where current vertex begins. indval_index is initially taken from instances counter whlie initializing matbeg for vertices*/
			cur_shifted_indval_index = cur_indval_index + (cluster_counter - 1)*vertex_2->instance_number; /* compansation for correct VERTEX_CLUSTER variable*/
			matind[cur_shifted_indval_index] = constraint_id; 
			matval[cur_shifted_indval_index] = -1;	/*Change to -1*/

			/* index increment */
			if(cluster_counter==number_of_clusters){
				vertex_1->indval_index++ ;
				vertex_2->indval_index++ ;
			}
			constraint_id++;
		}
		
		next_edge_NEW(&edge_iter);
	}

	/* QA for Type ii 
	printf("\n\nQA AFTER TYPE 2:\n\n");
	printf("\nmatbeg & matcnt values:\n");
	for(i=0; i<beg_size; i++){
		printf("Index[%d]: Beginning: %d, count: %d\n", i, matbeg[i], matcnt[i]);
	}
	printf("\nmatind & matval values:\n");
	for(i=0; i<ind_size; i++){
		printf("Index[%d]: Constraint: %d, Value: %d\n", i, matind[i], matval[i]);
	}
	*/
	
	printf("\n\nGoing to TYPE 3:\n\n");
	
	
	/* CONSTRAINTS TYPE iii & iv - handle vertices */
	
	
	/* Type iii constraints - 5*|E|*k -> k(5|E| + |V|) -1*/
	new_vertex_iterator(global_net, &ver_iter);
	for(i=0; i<vertices_num; i++){
		
		cur_vertex=ver_iter.currnet_vertex;

		sense[constraint_id]='E';
		rhs[constraint_id]=1;

		for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){
			cur_indval_index = cur_vertex->indval_index; /*Where current vertex begins. indval_index is initially taken from instances counter whlie initializing matbeg for vertices*/
			cur_shifted_indval_index = cur_indval_index + (cluster_counter - 1)*cur_vertex->instance_number; /* compansation for correct VERTEX_CLUSTER variable*/
			matind[cur_shifted_indval_index] = constraint_id; 
			matval[cur_shifted_indval_index] = 1;	/*Change to 1*/
		}
		
		constraint_id++;
		cur_vertex->indval_index++;
		next_vertex_NEW(&ver_iter);
	}


	/* Type iv constraints - k(5|E| + |V|) -> k(5|E| + 2|V|)*/
	
	for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){

		new_vertex_iterator(global_net, &ver_iter);
		sense[constraint_id]='G';
		rhs[constraint_id]=1;
		
		for(i=0; i<vertices_num; i++){
			cur_vertex=ver_iter.currnet_vertex;
			cur_indval_index = cur_vertex->indval_index; /*Where current vertex begins. indval_index is initially taken from instances counter whlie initializing matbeg for vertices*/
			cur_shifted_indval_index = cur_indval_index + (cluster_counter - 1)*cur_vertex->instance_number; /* compansation for correct VERTEX_CLUSTER variable*/
			matind[cur_shifted_indval_index] = constraint_id; 
			matval[cur_shifted_indval_index] = 1;	/*Change to 1*/
			next_vertex_NEW(&ver_iter);
		}
		constraint_id++;
	}

	/* Set variables' type (BINARY) */
	cnt = number_of_variables;
	for(i=0; i<number_of_variables; i++){
		indices[i] = i;
		ctype[i] = 'B';
	}


	/* QA */

	print_constraints(&edge_iter, &ver_iter, sense, rhs, matbeg, matcnt, matind, matval, number_of_clusters);
	printf("\nAllright then!\n");
}


void print_constraints(edge_iterator *edge_i, vertex_iterator *ver_i, char *sense, double *rhs, int *matbeg, int *matcnt, int *matind,	int *matval, int number_of_clusters){

	int edges_num, vertices_num;
	int i, j, cur_shifted_indval_index, constraint_id, cluster_counter;
	int edge_indval_index; /* TRY to eliminate constraint_id - replace with "constraint_id"*/
	Vertex *cur_vertex= NULL, *vertex_1, *vertex_2;
	Vertex **vertices_arr = global_net->vertices;
	Edge *cur_edge= NULL;
	edge_iterator edge_iter = *edge_i;
	vertex_iterator ver_iter = *ver_i;

	/* initialize CPLEX arrays */
	edges_num = global_net->totalEdgeNumber;
	vertices_num = global_net->size;

	/* Clean iterators index */
	clean_iterator_index(&ver_iter, &edge_iter);
	new_edge_iterator(global_net, &edge_iter);
	new_vertex_iterator(global_net, &ver_iter);

	constraint_id = 0;  /* G: SN: PAY ATTENTION!! I've been using "constraint_id" !!!*/
	printf("\nType 1 values:\n");
	for(i=0; i<edges_num; i++){
		
		cur_edge=edge_iter.currnet_edge;
		edge_indval_index = cur_edge->indval_index;
		vertex_1 = vertices_arr[cur_edge->id1];
		vertex_2 = vertices_arr[cur_edge->id2];
		printf("For edge %d(%c,%c): ", cur_edge->edge_id, cur_edge->id1 + 97, cur_edge->id2 + 97);
		for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){
			cur_vertex = vertex_1;
			
			for(j=1; j<=2; j++){
				printf("%dZ_%d_%d %dX_%c_%d %c %f   ",
						matval[edge_indval_index],
						cur_edge->edge_id,
						cluster_counter,
						matval[cur_vertex->indval_index + cur_vertex->instance_number*(cluster_counter-1)],
						cur_vertex->id+ 97,
						cluster_counter,		
						sense[constraint_id],
						rhs[constraint_id]);
				if(j==1) cur_vertex = vertex_2;
				constraint_id++;
			}
			cur_edge->indval_index++;
			printf("\n                 ");
		}
		vertex_1->indval_index++;
		vertex_2->indval_index++;
		next_edge_NEW(&edge_iter);
		printf("\n");
	}

	printf("Type ii values:\n");
	
	new_edge_iterator(global_net, &edge_iter);
	
	for(i=0; i<edges_num; i++){
		
		cur_edge=edge_iter.currnet_edge;
		edge_indval_index = cur_edge->indval_index;
		vertex_1 = vertices_arr[cur_edge->id1];
		vertex_2 = vertices_arr[cur_edge->id2];
		printf("For edge %d(%c,%c): ", cur_edge->edge_id, cur_edge->id1 + 97, cur_edge->id2 + 97);
		for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){
			cur_vertex = vertex_1;
			printf("For cluster: %d ", cluster_counter);
			printf("%dZ_%d_%d %dX_%c_%d %dX_%c_%d %c %f",
					matval[edge_indval_index],
					cur_edge->edge_id,
					cluster_counter,
					matval[vertex_1->indval_index + vertex_1->instance_number*(cluster_counter-1)],
					vertex_1->id+ 97,
					cluster_counter,
					matval[vertex_2->indval_index + vertex_2->instance_number*(cluster_counter-1)],
					vertex_2->id+ 97,
					cluster_counter,
					sense[constraint_id],
					rhs[constraint_id]);
			constraint_id++;
			cur_edge->indval_index++;
			printf("\n                 ");
		}
		vertex_1->indval_index++;
		vertex_2->indval_index++;
		next_edge_NEW(&edge_iter);
		printf("\n");
	}	
	
	printf("Type iii values:\n");
	new_vertex_iterator(global_net, &ver_iter);
	for(i=0; i<vertices_num; i++){
		
		cur_vertex=ver_iter.currnet_vertex;
		printf("For vertex %c: ", cur_vertex->id +97);

		for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){
			cur_shifted_indval_index = cur_vertex->indval_index + cur_vertex->instance_number*(cluster_counter-1);
			printf("%dX_%c_%d ",
					matval[cur_shifted_indval_index],
					cur_vertex->id+ 97,
					cluster_counter);
		}
		printf(" %c %f\n",sense[constraint_id], rhs[constraint_id]);
		constraint_id++;
		cur_vertex->indval_index++;
		next_vertex_NEW(&ver_iter);
	}

	printf("Type iv values:\n");
	for(cluster_counter=1; cluster_counter<=number_of_clusters; cluster_counter++){
		
		new_vertex_iterator(global_net, &ver_iter);
	
		printf("For cluster %d: ", cluster_counter);

		for(i=0; i<vertices_num; i++){
			cur_vertex=ver_iter.currnet_vertex;
			cur_shifted_indval_index = cur_vertex->indval_index + cur_vertex->instance_number*(cluster_counter-1);
			printf("%dX_%c_%d ",
					matval[cur_shifted_indval_index],
					cur_vertex->id+ 97,
					cluster_counter);
			next_vertex_NEW(&ver_iter);
		}
		printf(" %c %f\n",sense[constraint_id], rhs[constraint_id]);
		constraint_id++;
		
	}

	printf("\nQA is over, check for differences.");

}


void qa1(int op, int number_of_constraints, int beg_size, int ind_size, int *matbeg, int *matcnt, int *matind, int* matval, char *sense, double *rhs){
	
	int i, vertices_num = global_net->size;
	Vertex **vertices_arr = global_net->vertices;

	if(op==1){
		for(i=0; i<vertices_num; i++){
			printf("%d %d\n", vertices_arr[i]->indval_index -vertices_arr[i]->matbeg_id, vertices_arr[i]->instance_number);
		}
		return;
	}
	
	printf("\nmatbeg & matcnt values:\n");
	for(i=0; i<beg_size; i++){
		printf("Index[%d]: Beginning: %d, count: %d\n", i, matbeg[i], matcnt[i]);
	}
	if(op==2) return;
	
	printf("\nmatind & matval values:\n");
	for(i=0; i<ind_size; i++){
		printf("Index[%d]: Constraint: %d, Value: %d\n", i, matind[i], matval[i]);
	}

	printf("\nSense & RHS values:\n");
	for(i=0; i<number_of_constraints; i++){
		printf("Constraint #%d: Sense is:%c RHS is: %f\n", i, sense[i], rhs[i]);
	}
}